﻿using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.EntityFrameworkCore.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Organizations;
using Abp.UI;
using ARchGL.Platform.Authorization;
using ARchGL.Platform.Authorization.Roles;
using ARchGL.Platform.Authorization.Users;
using ARchGL.Platform.Core;
using ARchGL.Platform.EntityFrameworkCore;
using ARchGL.Platform.Organizations.Dto;
using ARchGL.Platform.Utils;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;

namespace ARchGL.Platform.Organizations
{
    /// <summary>
    /// 部门服务
    /// </summary>
    public class OrganizationUnitAppService : PlatformAppServiceBase, IOrganizationUnitAppService
    {
        private readonly OrganizationUnitManager organizationUnitManager;
        private readonly IRepository<OrganizationUnitExtend, long> organizationUnitRepository;
        private readonly IRepository<UserOrganizationUnitExtend, long> userOrganizationUnitRepository;
        private readonly IRepository<User, long> userRepository;
        public OrganizationUnitAppService(
            OrganizationUnitManager _organizationUnitManager,
            IRepository<OrganizationUnitExtend, long> _organizationUnitRepository,
            IRepository<UserOrganizationUnitExtend, long> _userOrganizationUnitRepository,
            IRepository<User, long> _userRepository)
        {
            organizationUnitManager = _organizationUnitManager;
            organizationUnitRepository = _organizationUnitRepository;
            userOrganizationUnitRepository = _userOrganizationUnitRepository;
            userRepository = _userRepository;
        }

        /// <summary>
        /// 获取部门
        /// </summary>
        /// <returns></returns>
        public async Task<PagedResultDto<OrganizationUnitDto>> GetOrganizationUnits(GetOrganizationUnitsInput input)
        {
            var query =
                from ou in organizationUnitRepository.GetAll()
                join uou in userOrganizationUnitRepository.GetAll() on ou.Id equals uou.OrganizationUnitId into g
                select new { ou, memberCount = g.Count() };

            query = query
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.ou.DisplayName.Contains(input.Filter) || x.ou.Description.Contains(input.Filter));

            var result = await query.PageByAsync(input).Result.ToListAsync();

            var parentIdList = result.Select(x => x.ou.ParentId ?? 0).Distinct().ToList();
            var parentList = organizationUnitRepository.GetAll().Where(x => parentIdList.Contains(x.Id));

            return new PagedResultDto<OrganizationUnitDto>(query.Count(),
                result.Select(item =>
                {
                    var dto = ObjectMapper.Map<OrganizationUnitDto>(item.ou);
                    dto.MemberCount = item.memberCount;
                    dto.ParentName = parentList.FirstOrDefault(x => x.Id == dto.ParentId)?.DisplayName;
                    return dto;
                }).OrderBy(x => x.DisplayName).ThenBy(x => x.Code).ToList());
        }

        /// <summary>
        /// 获取部门下的用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<OrganizationUnitUserListDto>> GetOrganizationUnitUsers(GetOrganizationUnitUsersInput input)
        {
            var query = from uou in userOrganizationUnitRepository.GetAll()
                        join ou in organizationUnitRepository.GetAll() on uou.OrganizationUnitId equals ou.Id
                        join user in UserManager.Users on uou.UserId equals user.Id
                        where uou.OrganizationUnitId == input.Id
                        select new { uou, user };

            var totalCount = await query.CountAsync();
            var items = await query.OrderBy(input.Sorting).PageBy(input).ToListAsync();

            return new PagedResultDto<OrganizationUnitUserListDto>(
                totalCount,
                items.Select(item =>
                {
                    var dto = ObjectMapper.Map<OrganizationUnitUserListDto>(item.user);
                    dto.UserId = item.user.Id;
                    dto.UserPrimaryId = item.user.PrimaryId;
                    dto.AddedTime = item.uou.CreationTime;
                    return dto;
                }).ToList());
        }

        /// <summary>
        /// 获取多个部门下的用户
        /// </summary>
        /// <param name="input">部门标识集合</param>
        /// <returns></returns>
        [RemoteService(false)]
        public async Task<List<OrganizationUnitUserListDto>> GetOrganizationUnitUsers(List<long> input)
        {
            var query = from uou in userOrganizationUnitRepository.GetAll()
                        join ou in organizationUnitRepository.GetAll() on uou.OrganizationUnitId equals ou.Id
                        join user in UserManager.Users on uou.UserId equals user.Id
                        where input.Contains(uou.OrganizationUnitId)
                        select new { user };

            var result = await query.Distinct().ToListAsync();
            return ObjectMapper.Map<List<OrganizationUnitUserListDto>>(result);
        }

        /// <summary>
        /// 创建部门 请调用 CreateOrganizationUnitExtend 接口
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>

        [Obsolete("创建部门请调用 CreateOrganizationUnitExtend 接口")]
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
#endif
        public async Task<OrganizationUnitDto> CreateOrganizationUnit(CreateOrganizationUnitInput input)
        {
            await HasOrganizationUnit(input.ParentId, input.DisplayName);

            var organizationUnit = ObjectMapper.Map<OrganizationUnitExtend>(input);
            organizationUnit.TenantId = AbpSession.TenantId;
            organizationUnit.PrimaryId = GuidGenerator.Create();
            await organizationUnitManager.CreateAsync(organizationUnit);
            await CurrentUnitOfWork.SaveChangesAsync();

            var descr = string.Empty;
            if (!input.Description.IsNullOrWhiteSpace())
                descr = ",Description=@Description";

            var dbContext = organizationUnitRepository.GetDbContext();
            var sql = $"UPDATE \"AbpOrganizationUnits\" SET Discriminator=@Discriminator{descr},Sort=@Sort,Level=@Level WHERE Id=@Id";

            if (!input.Description.IsNullOrWhiteSpace())
                dbContext.Execute(sql, "OrganizationUnitExtend", input.Description, input.Sort, input.Level, organizationUnit.Id);
            else
                dbContext.Execute(sql, "OrganizationUnitExtend", input.Sort, input.Level, organizationUnit.Id);

            return ObjectMapper.Map<OrganizationUnitDto>(organizationUnit);
        }

        /// <summary>
        /// 创建扩展部门
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
#endif
        public async Task<OrganizationUnitDto> CreateOrganizationUnitExtend(CreateOrganizationUnitInput input)
        {
            await HasOrganizationUnit(input.ParentId, input.DisplayName);

            var organizationUnit = ObjectMapper.Map<OrganizationUnitExtend>(input);
            organizationUnit.Code = await organizationUnitManager.GetNextChildCodeAsync(organizationUnit.ParentId);
            organizationUnit.PrimaryId = GuidGenerator.Create();
            organizationUnit.Id = await organizationUnitRepository.InsertAndGetIdAsync(organizationUnit);
            return ObjectMapper.Map<OrganizationUnitDto>(organizationUnit);
        }

        /// <summary>
        /// 编辑部门名称 请调用 UpdateOrganizationUnitExtend 接口
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [Obsolete("编辑部门请调用 UpdateOrganizationUnitExtend 接口")]
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
#endif
        public async Task<OrganizationUnitDto> UpdateOrganizationUnit(UpdateOrganizationUnitInput input)
        {
            var organizationUnit = await organizationUnitRepository.GetAsync(input.Id);
            organizationUnit.DisplayName = input.DisplayName;

            await HasOrganizationUnit(organizationUnit.ParentId, input.DisplayName, input.Id);
            await organizationUnitManager.UpdateAsync(organizationUnit);

            return await CreateOrganizationUnitDto(organizationUnit);
        }

        /// <summary>
        /// 编辑扩展部门
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
#endif
        public async Task<OrganizationUnitDto> UpdateOrganizationUnitExtend(UpdateOrganizationUnitInput input)
        {
            var organizationUnit = await organizationUnitRepository.GetAsync(input.Id);
            organizationUnit.Description = input.Description;
            organizationUnit.DisplayName = input.DisplayName;

            await HasOrganizationUnit(organizationUnit.ParentId, input.DisplayName, input.Id);
            await organizationUnitRepository.UpdateAsync(organizationUnit);

            return await CreateOrganizationUnitDto(organizationUnit);
        }

        /// <summary>验证同级目录下是否同名</summary>
        /// <returns></returns>
        private async Task<OrganizationUnitExtend> HasOrganizationUnit(long? parentId, string displayName, long id = 0)
        {
            var entity = await organizationUnitRepository.GetAll()
                .WhereIf(id > 0, x => x.Id != id)
                .Where(x => x.ParentId == parentId).FirstOrDefaultAsync(x => x.DisplayName == displayName);
            if (entity != null) throw new UserFriendlyException("已存在该部门，请重新输入");

            return entity;
        }

        /// <summary>
        /// 移动部门
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
#endif
        public async Task<OrganizationUnitDto> MoveOrganizationUnit(MoveOrganizationUnitInput input)
        {
            await organizationUnitManager.MoveAsync(input.Id, input.NewParentId);

            return await CreateOrganizationUnitDto(
                await organizationUnitRepository.GetAsync(input.Id)
                );
        }

        /// <summary>
        /// 删除部门
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
#endif
        public async Task DeleteOrganizationUnit(EntityDto<long> input)
        {
            await organizationUnitManager.DeleteAsync(input.Id);
        }

        /// <summary>
        /// 批量删除部门
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageOrganizationTree)]
        public async Task BatchDeleteOrganizationUnit(List<long> input)
        {
            foreach (var id in input)
            {
                await organizationUnitManager.DeleteAsync(id);
            }
        }

        /// <summary>
        /// 删除部门下的用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageMembers)]
#endif
        public async Task RemoveUserFromOrganizationUnit(UserToOrganizationUnitInput input)
        {
            await UserManager.RemoveFromOrganizationUnitAsync(input.UserId, input.OrganizationUnitId);
        }

        /// <summary>
        /// 将用户添加到指定部门
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
#if !DEBUG
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageMembers)]
#endif
        public async Task AddUsersToOrganizationUnit(UsersToOrganizationUnitInput input)
        {
            //获取组织机构信息
            var organization = organizationUnitRepository.FirstOrDefault(x => x.Id == input.OrganizationUnitId);

            foreach (var userId in input.UserIds)
            {
                //用户信息
                var userInfo = userRepository.FirstOrDefault(x => x.Id == userId);

                await AddToOrganizationUnitAsync(userInfo, organization);

                await UserManager.AddToOrganizationUnitAsync(userId, input.OrganizationUnitId);
            }
        }

        /// <summary>
        /// 查询用户
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [AbpAuthorize(AppPermissions.Pages_Administration_OrganizationUnits_ManageMembers)]
        public async Task<PagedResultDto<NameValueDto>> FindUsers(FindOrganizationUnitUsersInput input)
        {
            var userIdsInOrganizationUnit = userOrganizationUnitRepository.GetAll()
                .Where(uou => uou.OrganizationUnitId == input.OrganizationUnitId)
                .Select(uou => uou.UserId);

            var query = UserManager.Users
                .Where(u => !userIdsInOrganizationUnit.Contains(u.Id))
                .WhereIf(
                    !input.Filter.IsNullOrWhiteSpace(),
                    u =>
                        u.Name.Contains(input.Filter) ||
                        u.Surname.Contains(input.Filter) ||
                        u.UserName.Contains(input.Filter) ||
                        u.EmailAddress.Contains(input.Filter)
                );

            var userCount = await query.CountAsync();
            var users = await query
                .OrderBy(u => u.Name)
                .ThenBy(u => u.Surname)
                .PageBy(input)
                .ToListAsync();

            return new PagedResultDto<NameValueDto>(
                userCount,
                users.Select(u =>
                    new NameValueDto(
                        u.FullName + " (" + u.EmailAddress + ")",
                        u.Id.ToString()
                    )
                ).ToList()
            );
        }

        /// <summary>
        /// 获取部门(包括人员)
        /// </summary>
        /// <returns></returns>
        public async Task<object> QueryOrganizationUnitWithUsers(GetOrganizationUnitsInput input)
        {
            //查询用户对应部门
            var queryUser = from user in userRepository.GetAll()
                            join userOrgan in userOrganizationUnitRepository.GetAll() on user.Id equals userOrgan.UserId
                            join organ in organizationUnitRepository.GetAll() on userOrgan.OrganizationUnitId equals organ.Id
                            group new { userOrgan, organ } by user into gg
                            select new
                            {
                                user = gg.Key,
                                organ = gg.OrderByDescending(x => x.organ.Code).FirstOrDefault().organ
                            };

            var query =
                from ou in organizationUnitRepository.GetAll()
                .WhereIf(input.OrganizationUnitId > 0, x => x.Id == input.OrganizationUnitId)
                select new
                {
                    organ = new
                    {
                        ou.Id,
                        ou.PrimaryId,
                        ou.DisplayName,
                        ou.Code,
                        ou.Description,
                        ou.ParentId
                    },
                    userList = (from user_o in queryUser.Where(t => t.organ.Id == ou.Id)
                                select new
                                {
                                    user_o.user.Id,
                                    user_o.user.PrimaryId,
                                    user_o.user.UserName,
                                    user_o.user.Name,
                                    user_o.user.Position,
                                    user_o.user.PhoneNumber,
                                    user_o.user.EmailAddress,
                                    user_o.user.Avatar
                                }).ToList(),
                    MemberCount = 0,
                    ParentName = organizationUnitRepository.GetAll().Where(o => o.Id == ou.ParentId).DefaultIfEmpty().FirstOrDefault().DisplayName
                };

            //非管理权限筛选
            bool isAdmin = CheckInRole(StaticRoleNames.Tenants.Admin);
            if (!isAdmin)
            {
                var currentuser = await base.GetCurrentUserAsync();
                var originlist = await UserManager.GetOrganizationUnitsAsync(currentuser); //userOrganizationUnitRepository.GetAll().Where(x => x.UserId == currentuser.Id && x.).Select(x => x.OrganizationUnitId).ToList();
                var parentcode = originlist.Where(t => !t.ParentId.HasValue).FirstOrDefault()?.Code;
                query = query.WhereIf(!parentcode.IsNullOrWhiteSpace(), x => x.organ.Code.StartsWith(parentcode))
                    .WhereIf(parentcode.IsNullOrWhiteSpace(), x => false);
            }

            query = query
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.ParentName.Contains(input.Filter) || x.organ.DisplayName.Contains(input.Filter) || x.organ.Description.Contains(input.Filter));

            var result = await query.OrderBy(x => x.organ.Id).PageBy(input).ToListAsync();
            //.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();

            //筛选没有部门的人员名单
            var queryNoOrganUser = (from user in userRepository.GetAll().Where(u => !userOrganizationUnitRepository.GetAll().Any(y => y.UserId == u.Id))
                                    select new
                                    {
                                        user.Id,
                                        user.PrimaryId,
                                        user.UserName,
                                        user.Name,
                                        user.Position,
                                        user.PhoneNumber,
                                        user.EmailAddress,
                                        user.Avatar
                                    }).ToList();

            var dic = new Dictionary<string, object>
            {
                ["organ"] = new { Id = 0, PrimaryId = Guid.Empty, DisplayName = "其他" }
            };
            if (queryNoOrganUser.Any())
                dic["userList"] = queryNoOrganUser.ToList();
            else
                dic["userList"] = new object[] { };
            dic["MemberCount"] = queryNoOrganUser.Count();
            dic["ParentName"] = "";

            var queryResult = query.Union(new object[] { dic }.ToList());

            return new PagedResultDto<object>(
                query.Count(),
                queryResult.ToList()
            );

            //return result;
        }

        /// <summary>
        /// 组织架构：移动
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public void MoveOrganizationBySort(MoveOrganizationInput input)
        {
            if (input == null || input.TargetOrganId == 0)
                throw new UserFriendlyException("组织架构不存在,请检查后再试");

            //移动对象
            OrganizationUnitExtend organ = organizationUnitRepository.FirstOrDefault(x => x.Id == input.TargetOrganId);
            if (organ == null)
                throw new UserFriendlyException("组织架构不存在,请检查后再试");

            //原父级
            OrganizationUnitExtend organParent = organ.ParentId > 0 ? organizationUnitRepository.FirstOrDefault(x => x.Id == organ.ParentId) : null;
            //目标父级别
            OrganizationUnitExtend targetParent = input.TargetParentId > 0 ? organizationUnitRepository.FirstOrDefault(x => x.Id == input.TargetParentId) : null;
            //目标前一个Sort
            OrganizationUnitExtend targetBefore = input.TargetBeforeId > 0 ? organizationUnitRepository.FirstOrDefault(x => x.Id == input.TargetBeforeId) : null;

            int beforeSort = targetBefore != null ? targetBefore.Sort : 0;

            #region step1.更新父级
            if (targetParent != organParent)
            {
                organ.Parent = targetParent;
                // organ.ParentId = targetParent == null ? null : targetParent.Id;
                organ = organizationUnitRepository.Update(organ);
            }
            #endregion

            #region step2.确定更新范围(>目标排序)

            //查询需要更新的所有项
            var queryList = organizationUnitRepository.GetAll();
            if (targetParent != null)
            {
                queryList = queryList.Where(x => x.ParentId == targetParent.Id);
            }
            else
            {
                queryList = queryList.Where(x => !x.ParentId.HasValue || x.ParentId <= 0);
            }
            queryList = queryList.Where(x => x.Sort > beforeSort).OrderBy(x => x.Sort);
            if (queryList.Any())
            {
                //更新自己
                int sort = beforeSort + 1;
                organ.Sort = sort;
                organizationUnitRepository.Update(organ);

                var queryOther = queryList.Where(x => x.Id != organ.Id);
                if (queryOther.Any())
                {
                    //更新其他
                    sort = sort + 1;
                    //queryOther.ToList().ForEach(t =>
                    //{
                    //    t.Sort = sort;
                    //    organizationUnitRepository.Update(t);
                    //    sort++;
                    //});
                    var list = queryOther.ToList();
                    for (int i = 0; i < list.Count; i++)
                    {
                        var obj = list[i];
                        obj.Sort = sort;
                        organizationUnitRepository.Update(obj);
                        sort++;
                    }
                }
            }
            #endregion
        }

        /// <summary>
        /// 组织架构：批量移动
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public void BatchMoveOrganizationBySort(List<MoveOrganizationInput> input)
        {
            if (input == null || input.Count == 0)
                throw new UserFriendlyException("组织架构参数不正确，请检查后再试");
            input.ToList().ForEach(t => MoveOrganizationBySort(t));
        }

        /// <summary>
        /// 初始化组织架构的排序
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public void InitOrganizationBySort(MoveOrganizationInput input)
        {
            //目标父级别
            var targetParent = input.TargetParentId > 0 ? organizationUnitRepository.FirstOrDefault(x => x.Id == input.TargetParentId) : null;

            #region 确定更新范围(>目标排序)

            //查询需要更新的所有项
            var query = organizationUnitRepository.GetAll();
            if (targetParent != null)
            {
                query = query.Where(x => x.ParentId == targetParent.Id);
            }
            else
            {
                query = query.Where(x => !x.ParentId.HasValue);
            }
            query = query.OrderBy(x => x.Id);
            if (query.Any())
            {
                int index = 1;

                query.ToList().ForEach(t =>
                {
                    //递归
                    InitOrganizationBySort(new MoveOrganizationInput { TargetParentId = t.Id });

                    t.Sort = index;
                    organizationUnitRepository.Update(t);
                    index++;
                });
            }

            #endregion
        }

        #region Private method

        private async Task<OrganizationUnitDto> CreateOrganizationUnitDto(OrganizationUnit organizationUnit)
        {
            var dto = ObjectMapper.Map<OrganizationUnitDto>(organizationUnit);
            dto.MemberCount = await userOrganizationUnitRepository.CountAsync(x => x.OrganizationUnitId == organizationUnit.Id);
            return dto;
        }

        private async Task AddToOrganizationUnitAsync(User user, OrganizationUnitExtend ou)
        {
            var organizationUnitList = await UserManager.GetOrganizationUnitsAsync(user); //查询当前用户是否已存在该组织

            if (organizationUnitList.Any(x => x.Id == ou.Id)) return;

            await userOrganizationUnitRepository.InsertAsync(new UserOrganizationUnitExtend(AbpSession.TenantId, user, ou));
        }

        #endregion
    }
}
